package com.lingjtx.common.redis.service;

import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.thread.pooling.ObjectPoolTemplate;
import jakarta.annotation.Resource;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
public class RedisService implements IRedisService {

    @Resource(name = "redisObjectPoolTemplate")
    private ObjectPoolTemplate<RedisTemplate<String, Object>> redisObjectPoolTemplate;

    @Override
    public boolean delete(String key) {
        if (StringUtil.isNotEmpty(key)) {
            return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.delete(key));
        }
        return false;
    }

    @Override
    public void delete(String... keys) {
        if (keys == null || keys.length == 0) return;
        redisObjectPoolTemplate.consume(redisTemplate ->
                redisTemplate.delete(Arrays.stream(keys).collect(Collectors.toSet())));
    }

    @Override
    public void deletePattern(String pattern) {
        redisObjectPoolTemplate.consume(redisTemplate -> {
            Set<String> keys = redisTemplate.keys(pattern);
            if (!keys.isEmpty()) {
                redisTemplate.delete(keys);
            }
        });
    }

    @Override
    public boolean exists(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.hasKey(key));
    }

    @Override
    public boolean expire(String key, long timeout, TimeUnit unit) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.expire(key, timeout, unit));
    }

    @Override
    public boolean expire(String key, long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    @Override
    public Long getExpire(String key) {
        if (Objects.isNull(key)) return -2L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.getExpire(key));
    }

    @Override
    public Long getExpire(String key, TimeUnit timeUnit) {
        if (Objects.isNull(key)) return -2L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.getExpire(key, timeUnit));
    }

    @Override
    public boolean expireAt(String key, Date date) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.expireAt(key, date));
    }

    @Override
    public Set<String> keys(String pattern) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.keys(pattern));
    }

    @Override
    public boolean persist(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.persist(key));
    }

    @Override
    public String randomKey() {
        return redisObjectPoolTemplate.execute(RedisTemplate::randomKey);
    }

    @Override
    public void rename(String oldKey, String newKey) {
        redisObjectPoolTemplate.consume(redisTemplate -> {
            redisTemplate.rename(oldKey, newKey);
        });
    }

    @Override
    public boolean renameIfAbsent(String oldKey, String newKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.renameIfAbsent(oldKey, newKey));
    }

    @Override
    public DataType type(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.type(key));
    }

    @Override
    public byte[] dump(String key) {
        if (Objects.isNull(key)) return null;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.dump(key));
    }

    @Override
    public void set(String key, Object value) {
        if (Objects.isNull(key)) return;
        redisObjectPoolTemplate.consume(redisTemplate -> {
            redisTemplate.opsForValue().set(key, value);
        });
    }

    @Override
    public void set(String key, Object value, long timeout, TimeUnit unit) {
        if (Objects.isNull(key)) return;
        redisObjectPoolTemplate.consume(redisTemplate -> {
            redisTemplate.opsForValue().set(key, value, timeout, unit);
        });
    }

    @Override
    public void set(String key, Object value, long timeout) {
        if (Objects.isNull(key)) return;
        set(key, value, timeout, TimeUnit.SECONDS);
    }

    @Override
    public Boolean setIfAbsent(String key, Object value) {
        if (Objects.isNull(key)) return false;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForValue().setIfAbsent(key, value));
    }

    @Override
    public Boolean setIfAbsent(String key, Object value, long timeout, TimeUnit unit) {
        if (Objects.isNull(key)) return false;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit));
    }

    @Override
    public Boolean setIfAbsent(String key, Object value, long timeout) {
        if (Objects.isNull(key)) return false;
        return setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }

    @Override
    public Object get(String key) {
        if (Objects.isNull(key)) return null;
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            if (Objects.equals(redisTemplate.type(key), DataType.STRING)) {
                return redisTemplate.opsForValue().get(key);
            }
            return null;
        });
    }

    @Override
    public Object getAndSet(String key, Object value) {
        if (Objects.isNull(key)) return null;
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            if (Objects.equals(redisTemplate.type(key), DataType.STRING)) {
                return redisTemplate.opsForValue().getAndSet(key, value);
            }
            return null;
        });
    }

    @Override
    public List<Object> multiGet(String... keys) {
        if (keys == null || keys.length == 0) return null;
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForValue().multiGet(Arrays.stream(keys).collect(Collectors.toSet())));
    }

    @Override
    public Long increment(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            try {
                return redisTemplate.opsForValue().increment(key);
            } catch (Exception e) {
                return null;
            }
        });
    }

    @Override
    public Long increment(String key, long delta) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForValue().increment(key, delta));
    }

    @Override
    public Double increment(String key, double delta) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            try {
                return redisTemplate.opsForValue().increment(key, delta);
            } catch (Exception e) {
                return null;
            }
        });
    }

    @Override
    public Long decrement(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForValue().decrement(key));
    }

    @Override
    public Long decrement(String key, long delta) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForValue().decrement(key, delta));
    }

    @Override
    public Integer append(String key, String value) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForValue().append(key, value));
    }

    @Override
    public Long size(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForValue().size(key));
    }

    @Override
    public Long hmDelete(String key, String... hashKeys) {
        if (hashKeys == null || hashKeys.length == 0) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            return hashOperations.delete(key, hashKeys);
        });
    }

    @Override
    public Boolean hmExists(String key, String hashKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            return hashOperations.hasKey(key, hashKey);
        });
    }

    @Override
    public Object hmGet(String key, String hashKey) {
        if (Objects.isNull(key) || Objects.isNull(hashKey)) return null;
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            if (Objects.equals(redisTemplate.type(key), DataType.HASH)) {
                HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
                return hashOperations.get(key, hashKey);
            }
            return null;
        });
    }

    @Override
    public List<Object> hmMultiGet(String key, Collection<String> hashKeys) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            if (Objects.equals(redisTemplate.type(key), DataType.HASH)) {
                HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
                return hashOperations.multiGet(key, hashKeys);
            }
            return null;
        });
    }

    @Override
    public List<Object> hmMultiGet(String key, String... hashKeys) {
        if (hashKeys == null || hashKeys.length == 0) return null;
        return hmMultiGet(key, Arrays.stream(hashKeys).collect(Collectors.toSet()));
    }

    @Override
    public Long hmIncrement(String key, String hashKey, long delta) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            try {
                HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
                return hashOperations.increment(key, hashKey, delta);
            } catch (Exception e) {
                return null;
            }
        });
    }

    @Override
    public Double hmIncrement(String key, String hashKey, double delta) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            try {
                HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
                return hashOperations.increment(key, hashKey, delta);
            } catch (Exception e) {
                return null;
            }
        });
    }

    @Override
    public Long hmSize(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            return hashOperations.size(key);
        });
    }

    @Override
    public void hmPutAll(String key, Map<String, Object> m) {
        if (Objects.isNull(key)) return;
        redisObjectPoolTemplate.consume(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            hashOperations.putAll(key, m);
        });
    }

    @Override
    public void hmPut(String key, String hashKey, Object value) {
        if (Objects.isNull(key)) return;
        redisObjectPoolTemplate.consume(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            hashOperations.put(key, hashKey, value);
        });
    }

    @Override
    public Boolean hmPutIfAbsent(String key, String hashKey, Object value) {
        if (Objects.isNull(key)) return false;
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            return hashOperations.putIfAbsent(key, hashKey, value);
        });
    }

    @Override
    public Set<String> hmKeys(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            return hashOperations.keys(key);
        });
    }

    @Override
    public List<Object> hmValues(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            return hashOperations.values(key);
        });
    }

    @Override
    public Map<String, Object> hmEntries(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            return hashOperations.entries(key);
        });
    }

    @Override
    public Cursor<Map.Entry<String, Object>> hmScan(String key, ScanOptions options) {
        return redisObjectPoolTemplate.execute(redisTemplate -> {
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            return hashOperations.scan(key, options);
        });
    }

    @Override
    public List<Object> lRange(String key, long start, long end) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().range(key, start, end));
    }

    @Override
    public void lTrim(String key, long start, long end) {
        redisObjectPoolTemplate.consume(redisTemplate -> {
            redisTemplate.opsForList().trim(key, start, end);
        });
    }

    @Override
    public Long lSize(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().size(key));
    }

    @Override
    public Long leftPush(String key, Object value) {
        if (Objects.isNull(key)) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().leftPush(key, value));
    }

    @Override
    public Long leftPushAll(String key, Collection<Object> values) {
        if (Objects.isNull(key) || CollectionUtils.isEmpty(values)) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().leftPushAll(key, values));
    }

    @Override
    public Long leftPushAll(String key, Object... values) {
        if (Objects.isNull(key) || values == null || values.length == 0) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().rightPushAll(key, values));
    }

    @Override
    public Long leftPushIfPresent(String key, Object value) {
        if (Objects.isNull(key)) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().leftPushIfPresent(key, value));
    }

    @Override
    public Long leftInsert(String key, Object pivot, Object value) {
        if (Objects.isNull(key)) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().leftPush(key, pivot, value));
    }

    @Override
    public Long rightPush(String key, Object value) {
        if (Objects.isNull(key)) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().rightPush(key, value));
    }

    @Override
    public Long rightPushAll(String key, Object... values) {
        if (Objects.isNull(key) || values == null || values.length == 0) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().rightPushAll(key, values));
    }

    @Override
    public Long rightPushAll(String key, Collection<Object> values) {
        if (Objects.isNull(key) || CollectionUtils.isEmpty(values)) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().rightPushAll(key, values));
    }

    @Override
    public Long rightPushIfPresent(String key, Object value) {
        if (Objects.isNull(key)) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().rightPushIfPresent(key, value));
    }

    @Override
    public Long rightInsert(String key, Object pivot, Object value) {
        if (Objects.isNull(key)) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().rightPush(key, pivot, value));
    }

    @Override
    public void lSet(String key, long index, Object value) {
        if (Objects.isNull(key)) return;
        redisObjectPoolTemplate.consume(redisTemplate -> {
            redisTemplate.opsForList().set(key, index, value);
        });
    }

    @Override
    public Long lRemove(String key, long count, Object value) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().remove(key, count, value));
    }

    @Override
    public Object lIndex(String key, long index) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().index(key, index));
    }

    @Override
    public Object leftPop(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().leftPop(key));
    }

    @Override
    public Object leftPop(String key, long timeout, TimeUnit unit) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().leftPop(key, timeout, unit));
    }

    @Override
    public Object leftPop(String key, long timeout) {
        return leftPop(key, timeout, TimeUnit.SECONDS);
    }

    @Override
    public Object rightPop(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().rightPop(key));
    }

    @Override
    public Object rightPop(String key, long timeout, TimeUnit unit) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().rightPop(key, timeout, unit));
    }

    @Override
    public Object rightPop(String key, long timeout) {
        return rightPop(key, timeout, TimeUnit.SECONDS);
    }

    @Override
    public Object rightPopAndLeftPush(String sourceKey, String destinationKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey));
    }

    @Override
    public Long sAdd(String key, Object... values) {
        if (key == null || values == null || values.length == 0) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().add(key, values));
    }

    @Override
    public Long sRemove(String key, Object... values) {
        if (values == null || values.length == 0) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().remove(key, values));
    }

    @Override
    public Object sPop(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().pop(key));
    }

    @Override
    public List<Object> sPop(String key, long count) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().pop(key, count));
    }

    @Override
    public Boolean sMove(String srcKey, Object member, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().move(srcKey, member, destKey));
    }

    @Override
    public Long sSize(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().size(key));
    }

    @Override
    public Boolean sIsMember(String key, Object value) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().isMember(key, value));
    }

    @Override
    public Set<Object> sIntersect(String key, String otherKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().intersect(key, otherKey));
    }

    @Override
    public Set<Object> sIntersect(String key, Collection<String> otherKeys) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().intersect(key, otherKeys));
    }

    @Override
    public Long sIntersectAndStore(String key, String otherKey, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().intersectAndStore(key, otherKey, destKey));
    }

    @Override
    public Long sIntersectAndStore(String key, Collection<String> otherKeys, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().intersectAndStore(key, otherKeys, destKey));
    }

    @Override
    public Set<Object> sUnion(String key, String otherKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().union(key, otherKey));
    }

    @Override
    public Set<Object> sUnion(String key, Collection<String> otherKeys) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().union(key, otherKeys));
    }

    @Override
    public Long sUnionAndStore(String key, String otherKey, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey));
    }

    @Override
    public Long sUnionAndStore(String key, Collection<String> otherKeys, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey));
    }

    @Override
    public Set<Object> sDifference(String key, String otherKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().difference(key, otherKey));
    }

    @Override
    public Set<Object> sDifference(String key, Collection<String> otherKeys) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().difference(key, otherKeys));
    }

    @Override
    public Long sDifferenceAndStore(String key, String otherKey, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().differenceAndStore(key, otherKey, destKey));
    }

    @Override
    public Long sDifferenceAndStore(String key, Collection<String> otherKeys, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().differenceAndStore(key, otherKeys, destKey));
    }

    @Override
    public Set<Object> sMembers(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().members(key));
    }

    @Override
    public Object sRandomMember(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().randomMember(key));
    }

    @Override
    public Set<Object> sDistinctRandomMembers(String key, long count) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().distinctRandomMembers(key, count));
    }

    @Override
    public List<Object> sRandomMembers(String key, long count) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().randomMembers(key, count));
    }

    @Override
    public Cursor<Object> sScan(String key, ScanOptions options) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForSet().scan(key, options));
    }

// ---------------- ZSet ----------------

    @Override
    public Boolean zAdd(String key, Object value, double score) {
        if (key == null) return false;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().add(key, value, score));
    }

    @Override
    public Long zAdd(String key, Set<ZSetOperations.TypedTuple<Object>> tuples) {
        if (key == null) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().add(key, tuples));
    }

    @Override
    public Long zRemove(String key, Object... values) {
        if (values == null || values.length == 0) return 0L;
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().remove(key, values));
    }

    @Override
    public Double zIncrementScore(String key, Object value, double delta) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().incrementScore(key, value, delta));
    }

    @Override
    public Long zRank(String key, Object value) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().rank(key, value));
    }

    @Override
    public Long zReverseRank(String key, Object value) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().reverseRank(key, value));
    }

    @Override
    public Set<Object> zRange(String key, long start, long end) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().range(key, start, end));
    }

    @Override
    public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key, long start, long end) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().rangeWithScores(key, start, end));
    }

    @Override
    public Set<Object> zRangeByScore(String key, double min, double max) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().rangeByScore(key, min, max));
    }

    @Override
    public Set<ZSetOperations.TypedTuple<Object>> zRangeByScoreWithScores(String key, double min, double max) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max));
    }

    @Override
    public Set<Object> zRangeByScore(String key, double min, double max, long offset, long count) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().rangeByScore(key, min, max, offset, count));
    }

    @Override
    public Set<ZSetOperations.TypedTuple<Object>> zRangeByScoreWithScores(String key, double min, double max, long offset, long count) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max, offset, count));
    }

    @Override
    public Set<Object> zReverseRange(String key, long start, long end) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().reverseRange(key, start, end));
    }

    @Override
    public Set<ZSetOperations.TypedTuple<Object>> zReverseRangeWithScores(String key, long start, long end) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end));
    }

    @Override
    public Set<Object> zReverseRangeByScore(String key, double min, double max) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().reverseRangeByScore(key, min, max));
    }

    @Override
    public Set<ZSetOperations.TypedTuple<Object>> zReverseRangeByScoreWithScores(String key, double min, double max) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, min, max));
    }

    @Override
    public Set<Object> zReverseRangeByScore(String key, double min, double max, long offset, long count) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().reverseRangeByScore(key, min, max, offset, count));
    }

    @Override
    public Set<ZSetOperations.TypedTuple<Object>> zReverseRangeByScoreWithScores(String key, double min, double max, long offset, long count) {
        return redisObjectPoolTemplate.execute(redisTemplate -> redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, min, max, offset, count));
    }

    @Override
    public Long zCount(String key, double min, double max) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().count(key, min, max));
    }

    @Override
    public Long zSize(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().size(key));
    }

    @Override
    public Long zCard(String key) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().zCard(key));
    }

    @Override
    public Double zScore(String key, Object value) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().score(key, value));
    }

    @Override
    public Long zRemoveRange(String key, long start, long end) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().removeRange(key, start, end));
    }

    @Override
    public Long zRemoveRangeByScore(String key, double min, double max) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().removeRangeByScore(key, min, max));
    }

    @Override
    public Long zUnionAndStore(String key, String otherKey, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey));
    }

    @Override
    public Long zUnionAndStore(String key, Collection<String> otherKeys, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey));
    }

    @Override
    public Long zIntersectAndStore(String key, String otherKey, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().intersectAndStore(key, otherKey, destKey));
    }

    @Override
    public Long zIntersectAndStore(String key, Collection<String> otherKeys, String destKey) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().intersectAndStore(key, otherKeys, destKey));
    }

    @Override
    public Cursor<ZSetOperations.TypedTuple<Object>> zScan(String key, ScanOptions options) {
        return redisObjectPoolTemplate.execute(redisTemplate ->
                redisTemplate.opsForZSet().scan(key, options));
    }
}
